
import { State } from "./AState";
import { HSMBase, UpdateResult } from "./HSMBase";
/**
 * 状态机更新完后会生成一个Action的序列，让前面的优先级肯定最高.
 * Action执行返回值会出现终止。
 * 整个游戏维持一个Action序列数组 sequence:Record<string,Action[]>;也方便在超cpu之后的处理.什么该停
 */
export class HierarchicalStateMachine<T extends IStateArg = IStateArg> extends State<T>
{

    private  states:State[]=[];   // 当前状态机的所有状态
    private  initialState!:State;
    private  currentState?:State;
    private  components:HierarchicalStateMachine[]=[];
    constructor(states:State[])
    {
        super();
        this.addStates(...states);
        this.initialState = states[0];
        this.currentState = this.initialState;
    }


    public get CurrentState():State|undefined
    {
        return this.currentState;
    }
    public addStates(...states:State[])
    {
        for(let state of states)
        {
            state.setParent(this);
            state.index = this.states.length;
            this.states.push(state);
        }
        // this.states.push(...states);
    }

    public addComponents(componesnt:HierarchicalStateMachine[])
    {
        this.components.push(...componesnt);
        return this;
    }
    /**
     *
     * @returns 获取 状态机的所有状态栈信息
     */
    public getStateStack():IStateStack
    {

        const getStateStack=(hsm:HierarchicalStateMachine)=>{
            const state:IStateStack= {
                s: hsm.getStateIndex(),
                c:hsm.components.length==0?[]:_.map(hsm.components,e=>getStateStack(e))
            }
            return state
        }
        return getStateStack(this);
    }
    /**
     * 状态恢复
     * @param stateStack
     */
    public resetState(stateStack?:IStateStack)
    {
        if(stateStack)
        {
            this.recoverState(stateStack);
        }
        else
        {
            this.initState();
        }
    }
    private recoverState(stateStack:IStateStack)
    {
        const recover=(hsm:HierarchicalStateMachine ,state:number[],deep:number=0)=>
        {
            if(hsm.states)
            {
                const idx = state[deep];
                if(idx>=0)
                {
                    hsm.currentState =  hsm.states[idx];
                    recover(hsm.states[idx] as any,state,deep+1);
                }
                else
                {
                    global.Log.Info(`[${deep}]_${JSON.stringify(_.map(hsm.states,e=>e.name))}--->${JSON.stringify(state)}`)
                    throw new Error(`状态恢复出错找不到状态 ${state[deep]}`);
                }
            }
        }

        const recoverStack=(hsm:HierarchicalStateMachine ,stateStack:IStateStack)=>
        {
            if(stateStack)
            {
                recover(hsm,stateStack.s);
            }
            else
            {
                throw new Error(`状态错误 无法恢复${JSON.stringify(hsm.getStates().map(e=>e.name))}`);
            }
            
           
            for(let i=0;i<hsm.components.length;i++)
            {
                recoverStack(hsm.components[i],stateStack.c[i]);
            }
        }
        recoverStack(this,stateStack);
    }
    private initState()
    {
        const init=(hsm:HierarchicalStateMachine )=>
        {
            if(hsm.states&& hsm.states.length>0)
            {
                hsm.currentState =  hsm.states[0];
                init(hsm.currentState as any);
            }
        }
        const initStack=(hsm:HierarchicalStateMachine  )=>
        {

            init(hsm);
            for(let i=0;i<hsm.components.length;i++)
            {
                initStack(hsm.components[i]);
            }
        }
        initStack(this);
    }
    public getStates():State[]
    {
        if(this.currentState)
        {
            return [this,...this.currentState.getStates()];
        }
        else
        {
            return [this];
        }
    }
    /**
     * 获取激活的状态索引
     * @returns
     */
    public getStateIndex():number[]
    {
        if(this.currentState)
        {
            let currentindex = this.currentState.index;
            return [currentindex,...this.currentState.getStateIndex()];
        }
        else
        {
            return [];
        }
    }
    public getComponentsState()
    {
        return _.map(this.components,c=>c.getStates());
    }
    private UpdateComponents(arg:T,result:UpdateResult)
    {
        for(const e of this.components)
        {
            const childresult = e.Update(arg);
            result.actions.push(...childresult.actions);
        }
    }
    //

    public Update(arg:T):UpdateResult
    {
        this.arg = arg;

        // 如果不在状态中,则使用初始状态
        let result = new UpdateResult();
        result.actions=this.getActions(arg);
        if(!this.currentState)
        {
            this.currentState = this.initialState;
            result.actions.push(...this.currentState.getEntryActions(arg));
            this.UpdateComponents(arg,result);
            return result;
        }

        // 尝试查找当前状态中的转换
        let triggeredTransition;
        for(const transition of this.currentState.getTransitions())
        {
            if(transition.isTriggered(arg))
            {
                triggeredTransition = transition;
                break;
            }
        }

        // 如果找到转换，则生成一个相应的结果结构

        if(triggeredTransition)
        {
            result.actions = [];
            result.transition = triggeredTransition;
            result.level = triggeredTransition.getLevel();
        }
        else
        {
            // 向下递归找到一个结果
            result = this.currentState.Update(arg);
        }

        // 检查结果中是否包含转换
        if(result.transition)
        {
            // 基于该层的动作
            if(result.level === 0)
            {
                // 添加正常动作(这可能是一个状态)

                // result.actions.push(...this.getActions(arg));
                // 当该转换就在当前层次上时，立即执行
                const targetState = result.transition.getTargetState();

                result.actions.push(...this.currentState.getExitActions(arg));
                result.actions.push(...result.transition.getActions(arg));
                if(targetState)
                {
                    result.actions.push(...targetState.getEntryActions(arg));

                }


                // 设置当前状态
                this.currentState = targetState;


                result.transition = undefined;
            }
            else if(result.level >0)
            {
                // 目标在更高的层次上
                result.actions.push(...this.currentState.getExitActions(arg));
                this.currentState = undefined;
                result.level-=1;
            }
            else
            {
                // 需要向下传递，向父级传递
                const targetstate = result.transition.getTargetState();
                if(targetstate)
                {
                    const targetMachine = targetstate.Parent;
                    result.actions.push(...result.transition.getActions(arg));
                    result.actions.push(...targetMachine.updateDown(arg,targetstate,-result.level));
                    result.transition = undefined;
                }
                else
                {
                    throw new Error(` transition ${result.transition} has no target state`);
                }

            }
        }
        else
        {
            // result.actions.push(...this.getActions(arg));
        }
        this.UpdateComponents(arg,result);
        return result;
    }


    updateDown(arg:T,state:State,level:number):Action[]
    {
        // 如果不在顶层，则继续递归
        let actions:Action[]=[];
        if (level >0)
        {
            actions = this.Parent.updateDown(arg,this,level-1);
        }
        else
        {
            // 否则不需要添加任何动作
            actions=[];
        }
        // 如果没有当前状态，则退出
        if(this.currentState)
        {
            actions.push(...this.currentState.getExitActions(arg));
        }

        // 移动到新状态，并返回所有的动作
        this.currentState = state;
        actions.push(...state.getEntryActions(arg));
        //actions.push(...state.getActions(arg));
        return actions;
    }

    public getLevel():number
    {
        if(this.Parent)
        {
            return this.Parent.getLevel()+1;
        }
        return 0;
    }
}
